/**
 * @file DecoderProcess.h
 * @author xag (xag@xa.com)
 * @brief
 * @version 1.0.10
 * @date 2023-08-09
 *
 * @copyright Copyright (c) 2007-2023, Guangzhou Xaircraft Technology Co., Ltd.
 *
 */
#pragma once
#include <linux/videodev2.h>
#include <linux/v4l2-controls.h>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <thread>

#include "DecoderFormat.h"

//using namespace kapok_common_basic;     // NOLINT

/* HEVC aka H.265 */
#define V4L2_PIX_FMT_HEVC     v4l2_fourcc('H', 'E', 'V', 'C')
/* TI NV12 10-bit, two bytes per channel */
#define V4L2_PIX_FMT_TI1210   v4l2_fourcc('T', 'I', '1', '2')
/* TI YUV422 10-bit, two bytes per channel */
#define V4L2_PIX_FMT_TI1610   v4l2_fourcc('T', 'I', '1', '6')

#define memzero(x)    memset(&(x), 0, sizeof (x))
#define MAX_TEST_FDS    10
#define MAX_FRAMES    1000
#define ALIGN(x, a)    (((x) + (a) - 1L) & ~((a) - 1L))
#define HW_ALIGN    64  // debug

#define MAX_DEC_OUTBUFS 2

#define DISPLAY_LAG 3

#define MAX_CAPBUFS_H264 16
#define MAX_DEC_CAPBUFS (MAX_CAPBUFS_H264 + DISPLAY_LAG)

#define D_MIN(a, b) ((a < b) ? a : b)

#define DEVICE_NAME "cardx"

// #define DRM

#ifdef DRM
static int drmfd1 = -1;
#endif

#define FMT_NUM_PLANES 1 /* Used when creating V4l2 buffers for capture buffers */
#define FMT_NUM_MJPEG_PLANES 3 /* Used when creating V4l2 buffers for capture buffers */

/*
 * @bo_handle: drm buffer handle
 * @dbuf_fd: dma buffer handle
 * @mapped: Pointer to mmap'ed buffer memory
 * @offset: offset of buffer
 * @length: Buffer length for munmap
 */
struct buffer {
    unsigned int bo_handle;
    int dbuf_fd;
    void *mapped;
    int offset;
    int length;
};

struct stream_context {
    size_t frame_sizes[MAX_FRAMES];
    int width;
    int height;
    int bitdepth;
    int num_bytes_per_pix;
    enum AVPixelFormat pix_fmt;
    enum AVCodecID codec;
};

/*
 *
 * @fourcc: The V4L2 fourcc value
 * @size_num: The numerator to multiply image size by
 * @size_den: The denominator to divide image size by
 */
struct output_format {
    uint32_t fourcc;
    int size_num;
    int size_den;
};

typedef struct tda4_decode {
  int fd;
  struct buffer outbufs[MAX_DEC_OUTBUFS];
  struct buffer capbufs[MAX_DEC_CAPBUFS];
  int max_frames;
  int enable_prof;
  int sleep_time;
  struct output_format fmt;
  int usedrmbuff;

  int n_outbufs;
  int n_capbufs;
  int nframes;
  int rdfd;
  int wrfd;
  struct stream_context str;

  char *h264_data;
  int h264_data_size;

  char *yuv_buf;
  int yuv_buf_len;
}DECODE_INFO_T;

namespace kapok_hardware_tidecoder {

class DecoderProcess {
     public: /* NOLINT */
        DecoderProcess();
        ~DecoderProcess();

        int DecoderInit(int vwidth, int vheight);
        int DecoderIniter(int vwidth, int vheight, int pix_fmt, int codec);
        int DecoderUnInit();
        int DecoderH264(char *h264_data, int size, char *yuv_buf, int len, uint64_t m_u64Pts);

     private: /* NOLINT */
        void errno_exit(const char *s);

        int handle_outbuf(int fd, int index, int rdfd, struct buffer buff,
                            struct stream_context *str, int nframes, int sleep_time,
                            char *h264_data, int h264_size);

        int handle_capbuf(int fd, int wrfd, int index, struct buffer buff[],
                            int save, struct stream_context *str,
                            struct output_format fmt, int usedrmbuff,
                            char *yuv_buf, int yuv_buf_size);

        int mainloop(void * ptr_decode_info);

        void uninit_device(int fd, struct buffer outbufs[],
                            struct buffer capbufs[], int *n_outbufs, int *n_capbufs,
                            int usedrmbuff);

        int create_drm_buffer(struct buffer *b,
                                unsigned int width, unsigned int height);

        int init_device(int fd, int rdfd,
                        struct stream_context *str, struct buffer outbufs[],
                        struct buffer capbufs[], int *n_outbufs, int *n_capbufs,
                        struct output_format format, int usedrmbuff);

        void close_device(int fd);

        int open_device(char *dev_name);

        int find_device(char *dev_name);

     private: /* NOLINT */
        int use_drm_capbuff = 0; /* Defaulting to use drm dss Capture Buffers */
        int num_devs = 1;
        int fds[MAX_TEST_FDS] = {0};
        char output_file[128] = {0};
        char drm_file_name[20] = "/dev/dri/card0";
        DECODE_INFO_T decode_info[1] = {0};
};

}    // namespace kapok_hardware_tidecoder
